﻿using System;
using System.Linq;
using CommonBehaviors.Actions;
using Portal.Core;
using Portal.Helpers;
using Portal.Managers;
using Portal.Settings;
using JetBrains.Annotations;
using Styx;
using Styx.CommonBot;
using Styx.TreeSharp;
using Styx.WoWInternals;
using Styx.WoWInternals.WoWObjects;
using Action = Styx.TreeSharp.Action;

namespace Portal.Specialisation
{
    [UsedImplicitly]
    internal class Frost : RotationBase
    {

        #region RotationBase Overrides
        public override WoWSpec KeySpec { get { return WoWSpec.MageFrost; } }
        public override string Name { get { return "Frost"; } }
        #endregion
        private static PortalSettings Settings { get { return PortalSettings.Instance; } }
        private static int _blizzardMobCount;
        private static WoWPoint _blizzardLocation;

        #region Honorbuddy's Rotation Overrides
        public override Composite Rotation
        {
            get
            {
                return new PrioritySelector(

                    new Decorator(ret => Me.CurrentTarget.HasDoNotDamageAura() || Me.HasAura("Ice Block"), new ActionAlwaysSucceed()),

                    new Decorator(ret => Settings.UseDeepFreeze, Spell.Cast("Deep Freeze")),
                    Spell.PreventDoubleCast("Frostfire Bolt", 0.3, on => Me.CurrentTarget, ret => !Me.IsCrowdControlled() && HaveBrainFreeze),
                    Spell.PreventDoubleCast("Ice Lance", 0.3, on => Me.CurrentTarget, ret => !Me.IsCrowdControlled() && (HaveFingersOfFrost || Me.CurrentTarget.HasAnyAura(SpellId.DeepFreeze, SpellId.FrostNova, 33395 /* Pet Freeze */, SpellId.RingOfFrost))),

                    Common.NonGcdCombat(),
                    
                    HandleBlizzardCancel(),

                    new Decorator(ret => Me.IsChanneling || Me.IsCasting ||  Common.LoSCheck, new ActionAlwaysSucceed()),
                    

                    Common.SetCounts, // Set counts for our AoE trigger
                    Common.Combat(), // Handles all of our utility / talent abilities.

                    // Icy Veins (unglyphed - 12472)
                    Spell.Cast(12472, ret => !Common.Hasted && !TalentManager.HasGlyph("Icy Veins") && !Me.IsMoving() && Me.CurrentTarget.IsBossOrPlayer()),
                    // Glyped version of icy veins - 131078
                    Spell.Cast(131078, ret => TalentManager.HasGlyph("Icy Veins") && NeedIcyVeins && Me.CurrentTarget.IsBossOrPlayer()), 

                    Spell.Cast("Presence of Mind", on => Me, ret => NeedPresenceOfMindOffensive),
                    Spell.PreventDoubleCast("Alter Time", 6.5, on => Me, ret => NeedAlterTimeOffensive),
                    
                    // AoE selector
                    new Decorator(ret => Settings.Frost_EnableAoE && Common._nearbyAoEUnitCount >= Settings.Frost_AoEUnitCount, HandleAoECombat()),
                    HandleSingleTarget()
                    );
            }

        }


        private static Composite HandleSingleTarget()
        {
            return new PrioritySelector(
                Spell.PreventDoubleCast("Summon Water Elemental", 2, ret => !Me.GotAlivePet),

                new Decorator(ret => !HaveFingersOfFrost && !HaveBrainFreeze, Common.HandleSingleTargetMageBombs()),

                Spell.PreventDoubleCastPetActionOnLocation("Freeze", 25, loc => Me.CurrentTarget.Location, ret => Me.CurrentTarget != null && NeedPetFreeze),

                Spell.Cast("Frozen Orb", ret => NeedFrozenOrb),

                new Decorator(ret => Settings.Frost_EnableAoE,
                   new PrioritySelector(
                    Spell.Cast("Fire Blast", ret => Common._nearbyAoEUnitCount >= 2 && Me.CurrentTarget.HasMyAura("Living Bomb") && TalentManager.HasGlyph("Inferno Blast")),
                    Spell.CastOnGround("Flamestrike", loc => Me.CurrentTarget.Location, ret => Common._nearbyAoEUnitCount >= 2 && !Me.CurrentTarget.IsMoving),
                    Common.HandleBombMultiDoT())),

                Spell.Cast("Frostbolt", ret => !HaveFingersOfFrost && !HaveBrainFreeze && !Me.CurrentTarget.IsDead && Me.CurrentTarget.Distance <= 40),

                // Filler - Moving
                //Spell.PreventDoubleCast("Blazing Speed", ThrottleTime, on => Me.CurrentTarget, ret => NeedBlazingSpeed, true),
                //Spell.PreventDoubleCast("Fire Blast", ThrottleTime, on => Me.CurrentTarget, ret => Me.IsMoving(), true),
                Spell.Cast("Ice Lance", ret => Me.IsMoving())
                );
        }


        private static Composite HandleAoECombat()
        {
            return new PrioritySelector(
                Spell.Cast("Frozen Orb", ret => NeedFrozenOrb),
                
                Spell.CastOnGround("Flamestrike", loc => Me.CurrentTarget.Location, ret => !Me.CurrentTarget.IsMoving),
                Spell.PreventDoubleCast("Fire Blast", 0.5, ret => Me.CurrentTarget.HasMyAura("Living Bomb") && TalentManager.HasGlyph("Inferno Blast")),
                Common.HandleBombMultiDoT(),

                //Spell.PreventDoubleCast("Arcane Explosion", ThrottleTime, ret => _unitsInArcaneExplosionRange >= _unitsNearTarget),
                Spell.PreventDoubleCastOnGround("Blizzard", 0.5, loc => Me.CurrentTarget.Location, ret => !Me.IsMoving() && Me.CurrentTarget != null),
                HandleSingleTarget()
                );
        }

        private static Composite HandleBlizzardCancel()
        {
            return new PrioritySelector(
                new Action(delegate
                {
                    if (Me.IsChanneling && Me.ChanneledCastingSpellId == SpellId.Blizzard)
                    {
                        // We're channeling
                        if (_blizzardLocation == WoWPoint.Empty)
                        {
                            // We haven't stored the location, so store it.
                            //Logger.DebugLog("Store Location..");
                            _blizzardLocation = Me.CurrentTarget.Location;
                            //Logger.DebugLog("Stored Location [{0}]", _blizzardLocation);
                        }
                        else
                        {
                            //Logger.DebugLog("Get unit count..");
                            // We've already got the location, check how many units are there

                            try
                            {
                                var countList = Unit.NearbyAttackableUnits(_blizzardLocation, 9);
                                _blizzardMobCount = countList != null ? countList.Count() : 99;
                            }
                            catch (Exception ex)
                            {
                                Log.Debug("Unit count failed with: {0}", ex);
                                _blizzardMobCount = 99;
                            }

                            if (HaveBrainFreeze)
                            {
                                Log.Debug("Brain Freeze - Cancelling");
                                SpellManager.StopCasting();
                            }

                            if (HaveFingersOfFrost)
                            {
                                Log.Debug("Fingers of Frost - Cancelling");
                                SpellManager.StopCasting();
                            }

                            if (_blizzardMobCount <= 4)
                            {
                                // Less than 4 units, cancel..
                                Log.Debug("Units under blizzard is now [{0} (Need 5)] - Cancelling", _blizzardMobCount);
                                SpellManager.StopCasting();
                            }
                            else
                            {
                                Log.Debug("[{0}] units in our blizzard, keep channelling...", _blizzardMobCount);
                                // 4 or more units. Return success to prevent tree traverse
                                return RunStatus.Success;
                            }
                        }
                    }

                    if (_blizzardLocation != WoWPoint.Empty && !Me.IsChanneling)
                    {
                        // We have hurricane location stored, but we're not channeling. Null it.
                        _blizzardLocation = WoWPoint.Empty;
                    }

                    return RunStatus.Failure;
                })
);

        }

        public override Composite PreCombat
        {
            get
            {
                return new PrioritySelector(
                    Common.PreCombat()
                    );
            }
        }

        #endregion

        #region Conditions
        private static bool HaveBrainFreeze { get { return Me.ActiveAuras.ContainsKey("Brain Freeze"); } }
        private static bool HaveFingersOfFrost { get { return Me.ActiveAuras.ContainsKey("Fingers of Frost"); } }
        //private static bool Hasted { get { return Me.HasAnyAura("Bloodlust", "Heroism", "Ancient Hysteria", "Time Warp"); } }
        //private static bool NeedFrostBoltDebuff { get { return Me.CurrentTarget != null && (Spell.StackCount(Me.CurrentTarget, "Frostbolt") < 3); } }
        private static bool NeedIcyVeins 
        {
            //Never
            //On Cooldown
            //On Boss Or Player
            //On Target Low HP
            //On Boss Or Player + BF/FoF Aura
            get
            {

                if (Settings.IcyVeinsCondition == 0) { return false; }

                if (Settings.IcyVeinsCondition == 1)
                {
                    return true;
                }

                if (Settings.IcyVeinsCondition == 2 && Me.CurrentTarget.IsBossOrPlayer())
                {
                    return true;
                }

                if (Settings.IcyVeinsCondition == 3 && Me.CurrentTarget.HealthPercent <= Settings.IcyVeinsLowHPValue)
                {
                    return true;
                }

                return Settings.IcyVeinsCondition == 4 && Me.CurrentTarget.IsBossOrPlayer() && Me.HasAnyAura("Brain Freeze", "Fingers of Frost");
            } 
        }
        private static bool NeedPetFreeze { get { return !Me.CurrentTarget.IsBoss() && Settings.Frost_UsePetFreeze && (Spell.GetAuraStackCount("Fingers of Frost") < 2); } }
        private static bool NeedFrozenOrb
        {
            get
            {
                return
                    Settings.Frost_FrozenOrbOnCooldown ||
                    (Settings.Frost_FrozenOrbOnTargetLowHP && Me.CurrentTarget.HealthPercent <= Settings.Frost_FrozenOrbOnTargetLowHPValue) ||
                    (Settings.Frost_FrozenOrbTargetStunnedRooted && (Me.CurrentTarget.IsStunned() || Me.CurrentTarget.IsRooted()));


                /* -- PureRotation method
                    (Me.CurrentTarget.HealthPercent >= 20 || Me.CurrentTarget.IsBossOrPlayer()) && !HaveFingersOfFrost &&

                    // Invocation
                    ((TalentManager.HasTalent(16) && Me.HasAura(116257) && Spell.GetAuraTimeLeft(116257, Me) > 12)
                    || !TalentManager.HasTalent(16));*/

            }
        }

        /*  0,On Target Low HP
            1,With Polymorph When Someone Healing
            2,On Cooldown
            3,On Boss Or Player
            4,Optimal Offensive DPS*/
        private static bool NeedPresenceOfMindOffensive { get
        {
            return Settings.UsePresenceOfMind && Settings.PresenceOfMindCondition == 4 && TalentManager.HasTalent(1) && 
                !Me.HasAura("Alter Time") && (Me.IsMoving() || Me.HasAura("Icy Veins"));
        } }

        private static bool NeedAlterTimeOffensive
        {
            get
            {
                return Settings.UseAlterTimeOffensive && 
                         ((Me.HasAura("Icy Veins") && Me.HasAllAuras("Fingers of Frost", "Brain Freeze")) 
                       || (Me.HasAura("Icy Veins") && Spell.GetAuraTimeLeft("Icy Veins") < 14 && Me.HasAnyAura("Fingers of Frost", "Brain Freeze"))
                       || (Me.HasAura("Icy Veins") && Spell.GetAuraTimeLeft("Icy Veins") < 9));
            }
        }
        #endregion

        #region Units

        #endregion

    }
}
